package com.webtair.dump4j.algorithm;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

import com.webtair.dump4j.core.Item;

public class PropertiesExtractorImpl implements PropertiesExtractor{
	int depth;
	Map<Object, Item> objectsPool = new HashMap<Object,Item>();
	Queue q;
	private static Set simpleClasses;
	static int maxRecNum = 10;
	{
		simpleClasses = new HashSet();
		simpleClasses.add(Boolean.class);
		simpleClasses.add(String.class);
		simpleClasses.add(Integer.class);
		simpleClasses.add(Double.class);
		simpleClasses.add(Long.class);
	}
	public Item extractAllProperties(Object object, int depth) {
		this.depth = depth;
		Item root = null;
		clear();
		if(depth<=maxRecNum){
			try {
				root = recursivelyBuildTree(object,0);
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else 
			root = buildTreeByQueue(object);
		root.setName("root");
		return root;
	}

	public void clear() {
		//FIXME: should be redesigned. workaround
		objectsPool.clear();
		Item.clearIdPool();
	}

	private Item buildTreeByQueue(Object object) {
		//FIXME: not working now. NEVER USE IT
		q = new LinkedList();
		Item root = null;
		q.add(object);
		while(q.size()>0){
			
		}
		return root;
	}

	private Item recursivelyBuildTree(Object object, int d) throws IllegalArgumentException, IllegalAccessException {
		if(object == null)
			return null;
		Item item = null;
		Item previous = objectsPool.get(object);
		if(previous != null){
			item = Item.shallowClone(previous);
		} else {
			Class cl = object.getClass();
			item = new Item(cl.getName(),"","");
			String value = getValueOfASimpleClass(object);
			if(value == null){
				item.setValue(null);
				objectsPool.put(object,item);
				if(d<=this.depth){
					Field[] fields = cl.getDeclaredFields();
					for (int i = 0; i < fields.length; i++) {
						Field field = fields[i];
						if(shouldSkip(field))
							continue;
						field.setAccessible(true);
						Object fieldValue = field.get(object);
						Item it = null;
						if(fieldValue!=null){
							it = recursivelyBuildTree(fieldValue,d+1);
						} else {
							it = new Item(field.getType().getName(),"","null");
							it.setLevel(d+1);
						}
						it.setName(field.getName());
						item.addChild(it);
					}
				}
			} else {
				item.setValue(value);
			}
		}
		item.setLevel(d);
		return item;
	}

	private String getValueOfASimpleClass(Object object) {
		if(object == null)
			return "null";
		if(simpleClasses.contains(object.getClass()))
			return ""+object;
		return null;
	}

	protected boolean shouldSkip(Field field){
		boolean result = false;
		return result;
	}

}
